package cn.autumnorange.app.gateway.security;

import cn.autumnorange.app.common.rpc.security.HttpSessionRequestCacheWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2SsoProperties;
import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoRestTemplateFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

// WebSecurityConfigurerAdapter如果配置为ResourceServerConfigurerAdapter
// 则访问service-hi 不需要权限的资源依旧会被拦截下来进行权限验证
// 配置为WebSecurityConfigurerAdapter zuul则会顺利通过feign层再转发到资源层
// zuul 详细filter配置 https://blog.csdn.net/wo18237095579/article/details/83543592
@Configuration
@EnableOAuth2Sso
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {

  //  @Bean
  //  public OAuth2RestTemplate oAuth2RestTemplate(
  //      OAuth2ClientContext oAuth2ClientContext,
  //      OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails) {
  //
  //    OAuth2RestTemplate oAuth2RestTemplate =
  //        new OAuth2RestTemplate(oAuth2ClientContext, oAuth2ProtectedResourceDetails);
  //  }

  // 仿写SsoSecurityConfigurer
  private static class OAuth2ClientAuthenticationConfigurer
      extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
    private OAuth2ClientAuthenticationProcessingFilter filter;

    OAuth2ClientAuthenticationConfigurer(OAuth2ClientAuthenticationProcessingFilter filter) {
      this.filter = filter;
    }

    public void configure(HttpSecurity builder) throws Exception {
      OAuth2ClientAuthenticationProcessingFilter ssoFilter = this.filter;
      ssoFilter.setSessionAuthenticationStrategy(
          (SessionAuthenticationStrategy)
              builder.getSharedObject(SessionAuthenticationStrategy.class));
      builder.addFilterAfter(ssoFilter, AbstractPreAuthenticatedProcessingFilter.class);
    }
  }

  @Autowired private ApplicationContext applicationContext;
  @Autowired private OAuth2SsoProperties oAuth2SsoProperties;

  private OAuth2ClientAuthenticationProcessingFilter oauth2SsoFilter() {
    OAuth2RestOperations restTemplate =
        ((UserInfoRestTemplateFactory)
                this.applicationContext.getBean(UserInfoRestTemplateFactory.class))
            .getUserInfoRestTemplate();
    ResourceServerTokenServices tokenServices =
        (ResourceServerTokenServices)
            this.applicationContext.getBean(ResourceServerTokenServices.class);
    OAuth2ClientAuthenticationProcessingFilter filter =
        new OAuth2ClientAuthenticationProcessingFilter(oAuth2SsoProperties.getLoginPath());
    filter.setRestTemplate(restTemplate);
    filter.setTokenServices(tokenServices);
    filter.setApplicationEventPublisher(this.applicationContext);
    GateWaySavedRequestAwareAuthenticationSuccessHandler
        gateWaySavedRequestAwareAuthenticationSuccessHandler =
            new GateWaySavedRequestAwareAuthenticationSuccessHandler();
    gateWaySavedRequestAwareAuthenticationSuccessHandler.setDefaultTargetUrl(
        gateWayAddress + "/" + userConsumerServiceId + "/loginSuccess");
    filter.setAuthenticationSuccessHandler(gateWaySavedRequestAwareAuthenticationSuccessHandler);
    return filter;
  }

  //  @Autowired
  //  private OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationProcessingFilter;
  @Value("${zuul.routes.app-user-consumer.serviceId}")
  private String userConsumerServiceId;

  @Value("${nginx-server}")
  private String gateWayAddress;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    //    自定义登录成功默认重定向路径
    SimpleUrlAuthenticationSuccessHandler simpleUrlAuthenticationSuccessHandler =
        new SimpleUrlAuthenticationSuccessHandler(
            gateWayAddress + "/" + userConsumerServiceId + "/loginSuccess");

    simpleUrlAuthenticationSuccessHandler.setAlwaysUseDefaultTargetUrl(true);

    OAuth2ClientAuthenticationProcessingFilter ssoFilter = oauth2SsoFilter();
    ssoFilter.setSessionAuthenticationStrategy(
        (SessionAuthenticationStrategy) http.getSharedObject(SessionAuthenticationStrategy.class));
    http.apply(new OAuth2ClientAuthenticationConfigurer(ssoFilter));


    http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
        .disable()
        .cors()
        .and().httpBasic().disable()
        .authorizeRequests()
        .antMatchers(HttpMethod.GET, "/testzuul")
        .hasAuthority("ROLE_admin")
        .anyRequest()
        .permitAll()
        .and()
        .formLogin()
        .successHandler(simpleUrlAuthenticationSuccessHandler);
    // 自定义RequestCache
    http.setSharedObject(RequestCache.class, new HttpSessionRequestCacheWrapper());

    //    http.authorizeRequests()
    //            .antMatchers("/login", "/oauth/**")
    //            .permitAll()
    //            .antMatchers("/wushaofeng")
    //            .authenticated()
    //            .and()
    //////               跨域设置 应该改为具体到对应客户端
    ////           .requestMatchers().antMatchers(HttpMethod.OPTIONS, "/oauth/**")
    //            .and()
    //            .csrf()
    //            .disable()
    ////            .cors().disable()
    //            .formLogin()
    ////            .loginPage("/login")
    //    ;
  }

  //  private CorsConfiguration buildConfig() {
  //    CorsConfiguration corsConfiguration = new CorsConfiguration();
  //    corsConfiguration.addAllowedOrigin("*"); // 1
  //    corsConfiguration.addAllowedHeader("*"); // 2
  //    corsConfiguration.setAllowCredentials(true);
  //    corsConfiguration.addAllowedMethod("*"); // 3
  //    return corsConfiguration;
  //  }
  //
  //  @Bean
  //  public CorsFilter corsFilter() {
  //    org.springframework.web.cors.UrlBasedCorsConfigurationSource source = new
  // org.springframework.web.cors.UrlBasedCorsConfigurationSource();
  //    source.registerCorsConfiguration("/**", buildConfig()); // 4
  //    return new CorsFilter(source);
  //  }

  //  /**
  //   * 注册check token服务
  //   *
  //   * @param details
  //   * @return
  //   */
  //  @Bean
  //  public RemoteTokenServices tokenService(OAuth2ProtectedResourceDetails details) {
  //    RemoteTokenServices tokenService = new RemoteTokenServices();
  //    tokenService.setCheckTokenEndpointUrl(checkTokenUrl);
  //    tokenService.setClientId(details.getClientId());
  //    tokenService.setClientSecret(details.getClientSecret());
  //    return tokenService;
  //  }

  //    public OAuth2ClientAuthenticationProcessingFilter
  // JsonOAuth2ClientAuthenticationProcessingFilter() {
  //        OAuth2ClientAuthenticationProcessingFilter filter = new
  // JsonOAuth2ClientAuthenticationProcessingFilter("callBack");
  ////    filter.setRestTemplate(oauth2RestTemplate);
  ////    filter.setTokenServices(tokenService);
  //
  //        return null;
  //    }
  // 源码ZuulServerAutoConfiguration SendErrorFilter BasicErrorController

  //  @Bean
  //  public SendErrorFilter sendErrorFilter() {
  //    return new GateWayErrorFilter();
  //  }


}
